package com.hellobike.haxing.modules.wms.facade.impl;

import com.hellobike.haxing.modules.product.entity.Sku;
import com.hellobike.haxing.modules.product.service.ISkuService;
import com.hellobike.haxing.modules.product.service.ISpuService;
import com.hellobike.haxing.modules.wms.dto.StockChangeDto;
import com.hellobike.haxing.modules.wms.entity.*;
import com.hellobike.haxing.modules.wms.enums.*;
import com.hellobike.haxing.modules.wms.exception.WmsServiceException;
import com.hellobike.haxing.modules.wms.facade.WmsAppPickFacade;
import com.hellobike.haxing.modules.wms.facade.WmsStockFacade;
import com.hellobike.haxing.modules.wms.service.*;
import com.hellobike.haxing.modules.wms.utils.ListUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Component("wmsAppPickFacade")
public class WmsAppPickFacadeImpl implements WmsAppPickFacade {

    @Autowired
    private IDeliveryOrderHeaderService deliveryOrderHeaderService;
    @Autowired
    private IDeliveryOrderDetailService deliveryOrderDetailService;
    @Autowired
    private IWaveService waveService;
    @Autowired
    private ISkuService skuService;
    @Autowired
    private ISpuService spuService;
    @Autowired
    private IPickHeaderService pickHeaderService;
    @Autowired
    private IPickTaskService pickTaskService;
    @Autowired
    private ISkuExtService skuExtService;
    @Autowired
    private IStockBatchLocService stockBatchLocService;
    @Autowired
    private WmsStockFacade wmsStockFacade;
    @Autowired
    private IContainerService containerService;
    @Autowired
    private ICodeHolderPointService codeHolderPointService;
    @Autowired
    private IDeliveryOrderBoxService deliveryOrderBoxService;
    @Autowired
    private IStockPickService stockPickService;

    @Override
    public PickHeader queryPickHeaderByOrderCode(String orderCode,Long warehouseId) throws WmsServiceException {
        if (StringUtils.isEmpty(orderCode)) {
            throw new WmsServiceException("订单号参数缺失");
        }
        DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getByOrderCode(orderCode,warehouseId);
        if (orderHeader == null) {
            throw new WmsServiceException("订单不存在：" + orderCode);
        }
        return pickHeaderService.getZTDByDeliveryOrderHeaderId(orderHeader.getId());
    }

    @Override
    public Container queryBox(String boxCode,Long warehouseId) throws WmsServiceException {
        return containerService.getByCode(boxCode,warehouseId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String pickByBoxAndSku(Long pickHeaderId, Long boxId, String barcode, Long warehouseId, Integer userId) throws WmsServiceException {
        if (pickHeaderId == null) {
            throw new WmsServiceException("参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        DeliveryOrderDetail orderDetail = deliveryOrderDetailService.getByHeaderIdAndBarcode(pickHeader.getDocId(), barcode);
        if (orderDetail == null) {
            throw new WmsServiceException("发货单明细不存在");
        }
        PickTask task = pickTaskService.getByDocLineIdAndDocOperId(orderDetail.getId(), pickHeader.getId());
        if (task == null) {
            throw new WmsServiceException("该商品拣货任务不存在");
        }
        if (task.getTaskStatus().equals(StockTaskStatusEnum.COMPLETED.getValue())) {
            throw new WmsServiceException("该商品拣货任务已完成,无法继续拣货");
        }
        Container box = containerService.getById(boxId);
        if (box == null) {
            throw new WmsServiceException("容器不存在");
        }
        if (ContainerStatusEnum.STOP_USING.getValue().equals(box.getContainerStatus())) {
            throw new WmsServiceException("该容器已停用");
        }
        if (ContainerStatusEnum.USING.getValue().equals(box.getContainerStatus()) ||
                ContainerStatusEnum.WAIT_RECEIVE.getValue().equals(box.getContainerStatus())) {
            if (!orderDetail.getOrderHeaderId().equals(box.getCurDocId())) {
                throw new WmsServiceException("该容器已被占用");
            }
        }
        BigDecimal qty = task.getQty();
        BigDecimal pickQty = Optional.ofNullable(task.getPickQty()).orElse(BigDecimal.ZERO);
        if (qty.compareTo(pickQty.add(BigDecimal.ONE)) < 0) {
            throw new WmsServiceException("该商品拣货已达上限，需要：" + qty + "份，已拣" + pickQty + "份");
        }
        task.setPickQty(pickQty.add(BigDecimal.ONE));
        //保存装箱信息
        DeliveryOrderBox orderBox = deliveryOrderBoxService.getByOrderDetailIdAndBoxId(orderDetail.getId(), boxId);
        if (null == orderBox) {
            orderBox = new DeliveryOrderBox();
            orderBox.setBoxId(box.getId());
            orderBox.setBoxCode(box.getContainerCode());
            orderBox.setBoxQty(BigDecimal.ONE);
            orderBox.setOrderDetailId(orderDetail.getId());
            orderBox.setOrderHeaderCode(orderDetail.getOrderHeaderCode());
            orderBox.setOrderHeaderId(orderDetail.getOrderHeaderId());
            orderBox.setShopId(orderDetail.getShopId());
            orderBox.setWarehouseId(warehouseId);
            orderBox.setSkuId(task.getSkuId());
            if (!deliveryOrderBoxService.save(orderBox)) {
                throw new WmsServiceException("保存装箱信息异常");
            }
        } else {
            orderBox.setBoxQty(orderBox.getBoxQty().add(BigDecimal.ONE));
            if (!deliveryOrderBoxService.updateById(orderBox)) {
                throw new WmsServiceException("更新装箱信息异常");
            }
        }
        //更新容器状态
        if (!ContainerStatusEnum.USING.getValue().equals(box.getContainerStatus())) {
            box.setContainerStatus(ContainerStatusEnum.USING.getValue());
            box.setCurDocId(orderDetail.getOrderHeaderId());
            box.setCurShopId(orderDetail.getShopId());
            if (!containerService.updateById(box)) {
                throw new WmsServiceException("更新容器异常");
            }
        }
        //更新拣货任务状态
        if (!StockTaskStatusEnum.DOING.getValue().equals(task.getTaskStatus())) {
            task.setTaskStatus(StockTaskStatusEnum.DOING.getValue());
        }
        if (!pickTaskService.updateById(task)) {
            throw new WmsServiceException("更新拣货任务状态异常");
        }
        if(pickHeader.getStartPickTime() == null){
            pickHeader.setStartPickTime(new Date());
            pickHeaderService.updateById(pickHeader);
        }
        return "该商品需要：" + qty.intValue() + "份，已拣" + task.getPickQty().intValue() + "份";
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String pickBySku(Long pickHeaderId, String barcode, Long warehouseId, Integer userId) throws WmsServiceException {
        if (pickHeaderId == null) {
            throw new WmsServiceException("参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        DeliveryOrderDetail orderDetail = deliveryOrderDetailService.getByHeaderIdAndBarcode(pickHeader.getDocId(), barcode);
        if (orderDetail == null) {
            throw new WmsServiceException("发货单明细不存在");
        }
        PickTask task = pickTaskService.getByDocLineIdAndDocOperId(orderDetail.getId(), pickHeader.getId());
        if (task == null) {
            throw new WmsServiceException("该商品拣货任务不存在");
        }
        if (task.getTaskStatus().equals(StockTaskStatusEnum.COMPLETED.getValue())) {
            throw new WmsServiceException("该商品拣货任务已完成,无法继续拣货");
        }
        BigDecimal qty = task.getQty();
        BigDecimal pickQty = Optional.ofNullable(task.getPickQty()).orElse(BigDecimal.ZERO);
        if (qty.compareTo(pickQty.add(BigDecimal.ONE)) < 0) {
            throw new WmsServiceException("该商品拣货已达上限，需要：" + qty + "份，已拣" + pickQty + "份");
        }
        task.setPickQty(pickQty.add(BigDecimal.ONE));
        //保存装箱信息
        DeliveryOrderBox orderBox = deliveryOrderBoxService.getByOrderDetailIdAndBoxId(orderDetail.getId(), -1L);
        if (null == orderBox) {
            orderBox = new DeliveryOrderBox();
            orderBox.setBoxId(-1L);
            orderBox.setBoxCode("NONE");
            orderBox.setBoxQty(BigDecimal.ONE);
            orderBox.setOrderDetailId(orderDetail.getId());
            orderBox.setOrderHeaderCode(orderDetail.getOrderHeaderCode());
            orderBox.setOrderHeaderId(orderDetail.getOrderHeaderId());
            orderBox.setShopId(orderDetail.getShopId());
            orderBox.setWarehouseId(warehouseId);
            orderBox.setSkuId(task.getSkuId());
            if (!deliveryOrderBoxService.save(orderBox)) {
                throw new WmsServiceException("保存装箱信息异常");
            }
        } else {
            orderBox.setBoxQty(orderBox.getBoxQty().add(BigDecimal.ONE));
            if (!deliveryOrderBoxService.updateById(orderBox)) {
                throw new WmsServiceException("更新装箱信息异常");
            }
        }
        //更新拣货任务状态
        if (!StockTaskStatusEnum.DOING.getValue().equals(task.getTaskStatus())) {
            task.setTaskStatus(StockTaskStatusEnum.DOING.getValue());
        }
        if(pickHeader.getStartPickTime() == null){
            pickHeader.setStartPickTime(new Date());
            pickHeaderService.updateById(pickHeader);
        }
        if (!pickTaskService.updateById(task)) {
            throw new WmsServiceException("更新拣货任务状态异常");
        }
        return "该商品需要：" + qty.intValue() + "份，已拣" + task.getPickQty().intValue() + "份";
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pickCompleted(Long pickHeaderId, Long warehouseId, Integer userId) throws WmsServiceException {
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        if (!pickHeader.getDocType().equals(DocTypeEnum.DO.getValue())) {
            throw new WmsServiceException("拣货单类型不是DO");
        }
        if (!pickHeader.getPickStatus().equals(PickStatusEnum.PUBLISHED.getValue())) {
            throw new WmsServiceException("拣货单状态异常");
        }
        DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(pickHeader.getDocId());
        if (orderHeader == null) {
            throw new WmsServiceException("订单不存在");
        }
        if (!orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.INIT.getValue()) &&
                !orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.PICKING.getValue())) {
            throw new WmsServiceException("订单状态异常");
        }
        List<PickTask> pickTasks = pickTaskService.getByDocOperId(pickHeader.getId());
        pickTasks.sort(Comparator.comparing(PickTask::getSkuId));
        for (PickTask pickTask : pickTasks) {
            if (pickTask.getTaskStatus().equals(StockTaskStatusEnum.COMPLETED.getValue())) {
                continue;
            }
            BigDecimal pickQty = pickTask.getPickQty();
            if (pickQty.compareTo(BigDecimal.ZERO) < 0) {
                throw new WmsServiceException("拣货数不能为负数");
            }
            if (pickQty.compareTo(pickTask.getQty()) > 0) {
                throw new WmsServiceException("拣货数不能为大于订单发货数");
            }
            //更新拣货任务
            pickTask.setTaskStatus(StockTaskStatusEnum.COMPLETED.getValue());
            if (!pickTaskService.updateById(pickTask)) {
                throw new WmsServiceException("更新拣货任务异常");
            }
            //回写发货数
            DeliveryOrderDetail orderDetail = deliveryOrderDetailService.getById(pickTask.getDocLineId());
            orderDetail.setSendQty(pickTask.getPickQty().intValue());
            if (!deliveryOrderDetailService.updateById(orderDetail)) {
                throw new WmsServiceException("回写发货数异常");
            }
        }
        subStockPick(pickTasks,warehouseId,userId);
        //清理无占用的box
        List<DeliveryOrderBox> deliveryOrderBoxes = deliveryOrderBoxService.getByOrderHeaderId(orderHeader.getId());
        if (ListUtil.isNotEmpty(deliveryOrderBoxes)) {
            Map<Long,List<DeliveryOrderBox>> boxMap = new HashMap<>();
            for (DeliveryOrderBox deliveryOrderBox : deliveryOrderBoxes) {
                if (deliveryOrderBox.getBoxId() != -1L) {
                    List<DeliveryOrderBox> orderBoxList = boxMap.computeIfAbsent(deliveryOrderBox.getBoxId(), k -> new ArrayList<>());
                    orderBoxList.add(deliveryOrderBox);
                }
            }
            if (boxMap.size()>0) {
                for (Map.Entry<Long, List<DeliveryOrderBox>> entry : boxMap.entrySet()) {
                    boolean isFree = true;
                    List<DeliveryOrderBox> orderBoxes = entry.getValue();
                    for (DeliveryOrderBox deliveryOrderBox : orderBoxes) {
                        if(deliveryOrderBox.getBoxQty().compareTo(BigDecimal.ZERO)>0){
                            isFree = false;
                            break;
                        }
                    }
                    if(isFree){
                        Container container = containerService.getById(entry.getKey());
                        if (container != null) {
                            container.setContainerStatus(ContainerStatusEnum.FREE.getValue());
                            container.setCurDocId(null);
                            container.setCurShopId(null);
                            containerService.updateById(container);
                        }
                        for (DeliveryOrderBox orderBox : orderBoxes) {
                            orderBox.setBoxId(-1L);
                            orderBox.setBoxCode("NONE");
                            deliveryOrderBoxService.updateById(orderBox);
                        }
                    }
                }
            }
        }
        //更新拣货单状态
        pickHeader.setPickStatus(PickStatusEnum.PICKED.getValue());
        pickHeader.setFinishPickTime(new Date());
        if (!pickHeaderService.updateById(pickHeader)) {
            throw new WmsServiceException("更新拣货单状态异常");
        }
        //更新发货单状态
        orderHeader.setOrderStatus(DeliveryOrderStatusEnum.PICKED.getValue());
        if (!deliveryOrderHeaderService.updateById(orderHeader)) {
            throw new WmsServiceException("更新发货单状态异常");
        }
    }

    private void subStockPick(List<PickTask> pickTasks, Long warehouseId, Integer userId) throws WmsServiceException {
        for (PickTask pickTask : pickTasks) {
            Sku sku = skuService.getByIdForReal(pickTask.getSkuId());
            if (sku == null) {
                sku = new Sku();
                sku.setId(pickTask.getSkuId());
                sku.setBarcode("none-"+pickTask.getSkuId());
                sku.setSkuCode("none-"+pickTask.getSkuId());
            }
            BigDecimal needSubQty = pickTask.getPickQty();
            if (needSubQty.compareTo(BigDecimal.ZERO) == 0) {//未拣货
                continue;
            }
            List<StockPick> stockPickList = stockPickService.getBySkuId(pickTask.getSkuId());
            if (ListUtil.isNullOrEmpty(stockPickList)) {
                throw new WmsServiceException("拣货库存未找到该商品:商品编码:" + sku.getSkuCode()+"商品编条码:"+sku.getBarcode());
            }
            BigDecimal totalQty = stockPickList.stream().map(StockPick::getPickQty).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            if (totalQty.compareTo(needSubQty) < 0) {
                throw new WmsServiceException("拣货库存不足：商品编码:" + sku.getSkuCode()+"商品编条码:"+sku.getBarcode());
            }
            for (StockPick stockPick : stockPickList) {
                if (needSubQty.compareTo(BigDecimal.ZERO) == 0) {//扣减结束
                    break;
                }
                if (stockPick.getPickQty().compareTo(needSubQty) >= 0) {
                    //扣减主库存
                    StockChangeDto stockChangeDto = new StockChangeDto();
                    stockChangeDto.setSkuId(pickTask.getSkuId());
                    stockChangeDto.setBatchId(stockPick.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                    stockChangeDto.setQty(needSubQty);
                    stockChangeDto.setLocId(stockPick.getLocId());
                    stockChangeDto.setWarehouseId(warehouseId);
                    stockChangeDto.setUserId(userId);
                    stockChangeDto.setStockId(stockPick.getId());
                    stockChangeDto = wmsStockFacade.subPickStock(stockChangeDto);
                    needSubQty = BigDecimal.ZERO;
                } else {
                    //扣减主库存
                    StockChangeDto stockChangeDto = new StockChangeDto();
                    stockChangeDto.setSkuId(pickTask.getSkuId());
                    stockChangeDto.setBatchId(stockPick.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                    stockChangeDto.setQty(stockPick.getPickQty());
                    stockChangeDto.setWarehouseId(warehouseId);
                    stockChangeDto.setUserId(userId);
                    stockChangeDto.setStockId(stockPick.getId());
                    stockChangeDto = wmsStockFacade.subPickStock(stockChangeDto);
                    needSubQty = needSubQty.subtract(stockPick.getPickQty());
                }
            }
            if (needSubQty.compareTo(BigDecimal.ZERO) > 0) {
                throw new WmsServiceException("拣货库存不足：商品编码:" + sku.getSkuCode()+"商品编条码:"+sku.getBarcode());
            }
        }
    }


    @Override
    public CodeHolderPoint queryPoint(String pointCode, Long warehouseId) throws WmsServiceException {
        return codeHolderPointService.getByCode(pointCode, warehouseId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void bindPoint(Long pickHeaderId, Long pointId, Long warehouseId, Integer userId) throws WmsServiceException {
        if (pickHeaderId == null) {
            throw new WmsServiceException("参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        CodeHolderPoint point = codeHolderPointService.getById(pointId);
        if (point == null) {
            throw new WmsServiceException("点位不存在");
        }
        if (point.getPointStatus().equals(PointStatusEnum.STOP_USING.getValue())) {
            throw new WmsServiceException("点位已停用");
        }
        if (PointStatusEnum.USING.getValue().equals(point.getPointStatus())) {
            if (!pickHeader.getDocId().equals(point.getCurDocId())) {
                throw new WmsServiceException("该码托点已被占用");
            }
        }
        DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(pickHeader.getDocId());
        if (orderHeader == null) {
            throw new WmsServiceException("订单不存在");
        }
        if (!orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.INIT.getValue()) &&
                !orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.PICKING.getValue())) {
            throw new WmsServiceException("订单状态异常");
        }
        if (!point.getPointStatus().equals(PointStatusEnum.USING.getValue())) {
            point.setPointStatus(PointStatusEnum.USING.getValue());
            point.setCurShopId(orderHeader.getShopId());
            point.setCurDocId(orderHeader.getId());
            if (!codeHolderPointService.updateById(point)) {
                throw new WmsServiceException("更新码托点异常");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String unPick(Long pickHeaderId, Long boxId, String barcode, Long warehouseId, Integer userId) throws WmsServiceException {
        if (pickHeaderId == null) {
            throw new WmsServiceException("参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        DeliveryOrderDetail orderDetail = deliveryOrderDetailService.getByHeaderIdAndBarcode(pickHeader.getDocId(), barcode);
        if (orderDetail == null) {
            throw new WmsServiceException("发货单明细不存在");
        }
        PickTask task = pickTaskService.getByDocLineIdAndDocOperId(orderDetail.getId(), pickHeader.getId());
        if (task == null) {
            throw new WmsServiceException("该商品拣货任务不存在");
        }
        if (task.getTaskStatus().equals(StockTaskStatusEnum.COMPLETED.getValue())) {
            throw new WmsServiceException("该商品拣货任务已完成,无法继续拣货");
        }
        BigDecimal qty = task.getQty();
        BigDecimal pickQty = Optional.ofNullable(task.getPickQty()).orElse(BigDecimal.ZERO);
        if (BigDecimal.ZERO.compareTo(pickQty.subtract(BigDecimal.ONE)) > 0) {
            throw new WmsServiceException("该商品撤销拣货已达上限，需要：" + qty + "份，已拣" + pickQty + "份");
        }
        task.setPickQty(pickQty.subtract(BigDecimal.ONE));
        if (boxId == null) {
            boxId = -1L;
        }
        //保存装箱信息
        DeliveryOrderBox orderBox = deliveryOrderBoxService.getByOrderDetailIdAndBoxId(orderDetail.getId(), boxId);
        if (null == orderBox) {
            throw new WmsServiceException("未找到该商品的装箱信息："+barcode);
        }
        if (BigDecimal.ZERO.compareTo(orderBox.getBoxQty().subtract(BigDecimal.ONE)) > 0) {
            throw new WmsServiceException("该商品撤销拣货已达上限，当前箱内数量：" + orderBox.getBoxQty() + "份");
        }
        orderBox.setBoxQty(orderBox.getBoxQty().subtract(BigDecimal.ONE));
        if (!deliveryOrderBoxService.updateById(orderBox)) {
            throw new WmsServiceException("更新装箱信息异常");
        }
        if (!pickTaskService.updateById(task)) {
            throw new WmsServiceException("更新拣货任务状态异常");
        }
        return "该商品需要：" + qty.intValue() + "份，已拣" + task.getPickQty().intValue() + "份";
    }
}
